#ifndef XLCOMM_NET_RPC_H_
#define XLCOMM_NET_RPC_H_

#include <stdint.h>

#include <string>

#include "xlcomm/copyable.h"
#include "xlcomm/net/buffer.h"

namespace xlcomm {
namespace net {

enum RpcType { RPC_TYPE_REQUEST, RPC_TYPE_RESPONSE, RPC_TYPE_UNKNOWN };

enum RpcErrorCode {
  RPC_ERR_OK,
  RPC_ERR_WRONG_PROTO,
  RPC_ERR_NO_SERVICE,
  RPC_ERR_NO_METHOD,
  RPC_ERR_INVALID_REQUEST,
  RPC_ERR_INVALID_RESPONSE,
  RPC_ERR_TIMEOUT
};

struct RpcMeta {
  RpcType type;
  int64_t id;
  std::string service;
  std::string method;
  std::string request;
  std::string response;
  RpcErrorCode errcode;

  void SerialToBuffer(Buffer& buff) const {
    buff.AppendInt8(type);

    buff.AppendInt64ToNet(id);

    buff.AppendInt32ToNet(static_cast<int>(service.length()));
    buff.Append(service);
    LOG_DEBUG << "--service:" << service;

    buff.AppendInt32ToNet(static_cast<int>(method.length()));
    buff.Append(method);
    LOG_DEBUG << "--method:" << method;

    buff.AppendInt32ToNet(static_cast<int>(request.length()));
    buff.Append(request);

    buff.AppendInt32ToNet(static_cast<int>(response.length()));
    buff.Append(response);

    buff.AppendInt8(errcode);
  }

  void DeserialFromBuffer(Buffer& buff) {
    type = static_cast<RpcType>(buff.ReadInt8());

    id = buff.ReadInt64ToHost();

    int len = buff.ReadInt32ToHost();
    service.assign(buff.ReaderPtr(), len);
    buff.HasRead(len);

    len = buff.ReadInt32ToHost();
    method.assign(buff.ReaderPtr(), len);
    buff.HasRead(len);

    len = buff.ReadInt32ToHost();
    request.assign(buff.ReaderPtr(), len);
    buff.HasRead(len);

    len = buff.ReadInt32ToHost();
    response.assign(buff.ReaderPtr(), len);
    buff.HasRead(len);

    errcode = static_cast<RpcErrorCode>(buff.ReadInt8());
  }
};

// class RpcMessage : copyable {
//  public:
//   ~RpcMessage() {}

//   // 传入一个对象，可以知道这个对象一共有哪些成员，分别是什么类型吗？
//   // https://www.zhihu.com/question/28849277
//   // 类似Java的反射机制。C++20还做不到。protobuf和Qt可以（生成元信息）
//   virtual bool SerialToString(std::string& msg_str) const = 0;
//   virtual bool DeserialFromString(const std::string& msg_str) = 0;
// };

class RpcParam {
 public:
  RpcParam() {}

  template <typename T>
  RpcParam& operator<<(const T& data) {
    size_t size = sizeof(data);
    if (size == 0) return *this;
    msg_.resize(size);  // TODO：添加多个成员，特殊符号分割
    memcpy(&msg_[0], &data, size);
    return *this;
  }

  const std::string& getMsg() const { return msg_; }

 private:
  std::string msg_;
};

class RpcParamReader {
 public:
  RpcParamReader(const std::string& msg) : msg_(msg) {}

  template <typename T>
  void getItemData(T& data) const {
    if (sizeof(data) != msg_.length()) return;
    memcpy(&data, &msg_[0], sizeof(data));
  }

 private:
  std::string msg_;
};

}  // namespace net
}  // namespace xlcomm

#endif  // XLCOMM_NET_RPC_H_